
#include "../deferredShaders.h"

struct VSAttrs {
    vec3 Position;
    vec3 Normal;
    vec2 TexCoords;
};

sampler MeshTextureSampler {
    MinFilter=trilinear;
    Aniso=4;
} TexDiffuse;

interface VSOutputs {
    vec4 normal;
    vec2 texCoords;
};

shader VSGBuffConstruct(in VSAttrs VSin : REG_POS, out VSOutputs vsout)
{
    vsout.normal.xyz=normalize(GlobalMatrices.NormalC*(LocalModel.NormalM*VSin.Normal));
    vsout.normal.w=Material.diffuse.w;
    vsout.texCoords=VSin.TexCoords;
 
    vec4 pos=LocalModel.ModelView*vec4(VSin.Position, 1.0f); 
    gl_Position=ProjectVertex(GlobalMatrices.Projection, GlobalMatrices.Camera*pos);
}

shader FSGbuffConstruct(in VSOutputs fsin, out vec4 diffuse : 0, out vec4 normal : 1)
{
    normal.xyz=normalize(fsin.normal.xyz);
    normal.w=fsin.normal.w;
    diffuse=texture(TexDiffuse, fsin.texCoords);
}


shader VSLightVol(in vec3 Position : REG_POS)
{
    gl_Position=ProjectVertex(GlobalMatrices.Projection, GlobalMatrices.Camera*(LocalModel.ModelView*vec4(Position, 1.0f)));
}


sampler GBuffSampler {
    Rect=1;
    MinFilter=point;
    MagFilter=point;
} GBuffDiffuse, GBuffNormal, GBuffDepth;

shader VSLightResolve(in vec2 sPos : REG_POS)
{
    gl_Position=vec4(sPos, 0, 1);
}

// Inverse Widht&Height of target texture, Near&Far planes
uniform vec2 gInverseWidthHeight;
uniform vec2 gNearFar;

uniform InverseMatrices {
    mat4 Projection;
    mat4 Camera;
    mat3 NormalC;
} GlobalInverse;

shader FSLightResolve(out vec4 color : 0)
{
    ivec2 texCoords=floor(gl_FragCoord.xy);
    vec4 normal=texelFetch(GBuffNormal, texCoords);
    
    vec3 ndcPos;
    ndcPos.xy=gl_FragCoord.xy*gInverseWidthHeight;
    ndcPos.z=texelFetch(GBuffDepth, texCoords).x;
    ndcPos=2.0f*ndcPos-1.0f;
    vec3 ePos=UnProjectVertex(GlobalInverse.Projection, ndcPos, gNearFar).xyz;
    
    if(dot(ePos-cLight.pos,normal.xyz)>0)
        discard;
    
    vec4 diffuse=texelFetch(GBuffDiffuse, texCoords);
    color.rgb=Lighting(normal.xyz, ePos, diffuse, normal.w);
    color.a=1.0f;
}


program GBuffConstruct {
    vs(410)=VSGBuffConstruct();
    fs(410)=FSGbuffConstruct() : in(early_fragment_tests);
};

program LightVol {
    vs(410)=VSLightVol();
};

program LightResolve {
    vs(410)=VSLightResolve();
    fs(410)=FSLightResolve() : in(early_fragment_tests);
};
